/**
 * 
 */
package com.xpec.c4.game.login;

import java.util.HashMap;
import java.util.Iterator;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.xpec.c4.game.utility.GUID;

/**
 * 管理玩家角色登入的管理器
 * <p>
 * 一個帳號同時可以有 50 隻角色登入遊戲, 第 51 隻角色登入時會踢掉第一隻.<br>
 * 有重複角色登入時會踢掉前一隻.
 * 
 * @author TW15010
 */
public class PlayerLoginManager {
	/** log4j object */
	private static final Log log = LogFactory.getLog(PlayerLoginManager.class);

	/**
	 * 允與同時連線數量
	 */
	private int maxConnectSession = 50;

	/**
	 * 用 account id 查詢角色登入資訊的 map<br>
	 * key: account id<br>
	 * value: {@link PlayerLoginManageInfo}
	 */
	private HashMap<GUID, PlayerLoginManageInfo> loginManageMap = new HashMap<GUID, PlayerLoginManageInfo>();

	/**
	 * 用 session id 查詢 account id 的 map<br>
	 * key: session id<br>
	 * value: account id
	 */
	private HashMap<GUID, GUID> sessionAccountMap = new HashMap<GUID, GUID>();

	/**
	 * 加入一個已經登入的角色
	 * 
	 * @param sessionId
	 * @param accountId
	 * @param playerId
	 *            要加入的角色 guid, 如果只是連線進來沒有選擇角色登入可以給 null
	 */
	public void addSession(GUID sessionId, GUID accountId, GUID playerId) {
		if (sessionId == null) {
			return;
		}

		if (accountId == null) {
			return;
		}

		sessionAccountMap.put(sessionId, accountId);

		PlayerLoginManageInfo manageInfo = loginManageMap.get(accountId);
		if (manageInfo == null) {
			manageInfo = new PlayerLoginManageInfo();
			loginManageMap.put(accountId, manageInfo);
		}

		if (playerId != null) {
			manageInfo.playerSessionMap.put(playerId, sessionId);
			manageInfo.sessionPlayerMap.put(sessionId, playerId);
		} else {
			manageInfo.sessionPlayerMap.put(sessionId, null);
		}

		if (log.isInfoEnabled()) {
			if (playerId == null) {
				log.info("account " + accountId + " add session " + sessionId + " ("
						+ manageInfo.sessionPlayerMap.size() + "/" + maxConnectSession + ")");
			} else {
				log.info("account " + accountId + " add player " + playerId + " ("
						+ manageInfo.playerSessionMap.size() + "/" + maxConnectSession + ")");
			}
		}
	}

	/**
	 * 將一個已經離線的玩家移除, 角色斷線呼叫這個
	 * 
	 * @param accountId
	 * @param playerId
	 */
	// public void removePlayer(GUID accountId, GUID playerId) {
	// if (accountId == null) {
	// return;
	// }
	//
	// if (playerId == null) {
	// return;
	// }
	//
	// // 先取得 player 對應的 session
	// PlayerLoginManageInfo manageInfo = loginManageMap.get(accountId);
	//
	// // 取不到資料
	// if (manageInfo == null) {
	// return;
	// }
	//
	// GUID sessionId = manageInfo.playerSessionMap.get(playerId);
	//
	// // 取不到 session id 表示指定指定角色並沒有登入, 後面也不用做了
	// if (sessionId == null) {
	// return;
	// }
	//
	// // 將角色的資料清掉
	// manageInfo.playerSessionMap.remove(playerId);
	// manageInfo.sessionPlayerMap.remove(sessionId);
	//
	// // 完全沒資料了就把資料結構清掉
	// if (manageInfo.playerSessionMap.size() == 0 &&
	// manageInfo.sessionPlayerMap.size() == 0) {
	// loginManageMap.remove(accountId);
	// }
	//
	// // 將對應角色 account 的 session 清掉
	// sessionAccountMap.remove(sessionId);
	// }

	/**
	 * 將一個沒有角色登入的連線移除, 如果只是還沒選擇角色登入的連線斷掉就呼叫這一個.
	 * <p>
	 * 如果有 player 也會連 player 一起移除.
	 * 
	 * @param sessionId
	 */
	public void removeSession(GUID sessionId) {
		if (sessionId == null) {
			return;
		}

		// 有 session 就一定會有 account, 取不到 account 後面的也不用做了
		GUID accountId = sessionAccountMap.get(sessionId);
		if (accountId == null) {
			return;
		}

		// 取得 account 的管理資訊
		PlayerLoginManageInfo manageInfo = loginManageMap.get(accountId);
		if (manageInfo == null) {
			return;
		}

		// 取得 session 對應的角色 id
		GUID playerId = manageInfo.sessionPlayerMap.get(sessionId);

		// 清除資料
		manageInfo.playerSessionMap.remove(playerId);
		manageInfo.sessionPlayerMap.remove(sessionId);

		// 完全沒資料了就把資料結構清掉
		if (manageInfo.playerSessionMap.size() == 0 && manageInfo.sessionPlayerMap.size() == 0) {
			loginManageMap.remove(accountId);
		}

		// 將對應角色 account 的 session 清掉
		sessionAccountMap.remove(sessionId);

		if (log.isInfoEnabled()) {
			log.info("account " + accountId + " remove session " + sessionId + " ("
					+ manageInfo.sessionPlayerMap.size() + "/" + maxConnectSession + ")");
		}
	}

	/**
	 * 取得指定帳號下的 session 數量
	 * 
	 * @param accountId
	 * @return
	 */
	public int getAccountSessionCount(GUID accountId) {
		if (accountId == null) {
			return 0;
		}

		// 取得 account 的管理資訊
		PlayerLoginManageInfo manageInfo = loginManageMap.get(accountId);
		if (manageInfo == null) {
			return 0;
		}

		int count = manageInfo.sessionPlayerMap.size();
		return count;
	}

	/**
	 * 取得指定帳號下的登入 player 數量
	 * 
	 * @param accountId
	 * @return
	 */
	public int getAccountLoginPlayerCount(GUID accountId) {
		if (accountId == null) {
			return 0;
		}

		// 取得 account 的管理資訊
		PlayerLoginManageInfo manageInfo = loginManageMap.get(accountId);
		if (manageInfo == null) {
			return 0;
		}

		int count = manageInfo.playerSessionMap.size();
		return count;
	}

	/**
	 * 取得指定 account 下的第一條連線 session id
	 * 
	 * @param accountId
	 * @return
	 */
	public GUID getAccountFirstSession(GUID accountId) {
		if (accountId == null) {
			return null;
		}

		// 取得 account 的管理資訊
		PlayerLoginManageInfo manageInfo = loginManageMap.get(accountId);
		if (manageInfo == null) {
			return null;
		}

		GUID sessionId = null;

		Iterator<GUID> it = manageInfo.sessionPlayerMap.keySet().iterator();
		if (it.hasNext()) {
			sessionId = it.next();
		}

		return sessionId;
	}

	/**
	 * 取得指定 account 下的第一條連線 session id
	 * 
	 * @param accountId
	 * @return
	 */
	public GUID getPlayerSession(GUID accountId, GUID playerId) {
		if (accountId == null) {
			return null;
		}

		if (playerId == null) {
			return null;
		}

		// 取得 account 的管理資訊
		PlayerLoginManageInfo manageInfo = loginManageMap.get(accountId);
		if (manageInfo == null) {
			return null;
		}

		GUID sessionId = manageInfo.playerSessionMap.get(playerId);

		return sessionId;
	}

	/**
	 * 指定的 player 是否存在
	 * 
	 * @param accountId
	 * @param playerId
	 * @return
	 */
	public boolean isPlayerExist(GUID accountId, GUID playerId) {
		if (accountId == null) {
			return false;
		}

		if (playerId == null) {
			return false;
		}

		PlayerLoginManageInfo manageInfo = loginManageMap.get(accountId);
		if (manageInfo == null) {
			return false;
		}

		if (manageInfo.playerSessionMap.containsKey(playerId)) {
			return true;
		}

		return false;
	}

	/**
	 * 檢查指定的 account 之下的 session 數量是否達到上限
	 * 
	 * @param accountId
	 * @return
	 */
	public boolean isAccountSessionFull(GUID accountId) {
		if (accountId == null) {
			return false;
		}

		PlayerLoginManageInfo manageInfo = loginManageMap.get(accountId);
		if (manageInfo == null) {
			return false;
		}

		// session 數量滿了
		if (manageInfo.sessionPlayerMap.size() >= maxConnectSession) {
			return true;
		}

		return false;
	}

	public int getMaxConnectSession() {
		return maxConnectSession;
	}
}
